home *** CD-ROM | disk | FTP | other *** search
/ Enigma Amiga Life 109 / EnigmaAmiga109CD.iso / dalla rivista / amiga.free / sorgenti vari / wolfedit2 2.0.4 source.sit / WolfEdit2 2.0.4 Source / UMapListDoc.p < prev    next >
Text File  |  1997-06-24  |  42KB  |  1,789 lines

  1. unit UMapListDoc;
  2.  
  3. interface
  4.     uses
  5.         UWolfDoc, UFree, UCursors;
  6.  
  7.     const
  8.  
  9.         firstEncounterCmd = 450;
  10.  
  11.     var
  12.  
  13.         gMultiEncounter: boolean;
  14.         gEncounter: integer;
  15.  
  16.     procedure IUMapListDoc;
  17.  
  18. implementation
  19.     uses
  20. {$IFC Demo}
  21.         UDemo, 
  22. {$ELSEC}
  23.         UEditDoors, UEditObjects, UEditEnemies, UEditOther, {}
  24.         UBigArt, UMultiArt, 
  25. {$ENDC}
  26.         UDialog, UXWindow, {}
  27.         UInstall, UMusic, UCTables, UEditArt, {}
  28.         UEditWalls, {}
  29.         UScenarioInfo;
  30.  
  31.     const
  32.  
  33.         noMemForLevelAlrtID = 128;
  34.         couldntOperateOnLevelAlrtID = 129;
  35.         buildFileBusyAlrtID = 137;
  36.         invalidAltNextLevelAlrtID = 143;
  37.         requiresVersionAlrtID = 144;
  38.         couldntSetCreatorAlrtID = 145;
  39.  
  40.         buildScenarioCmd = 250;
  41.         rebuildScenarioCmd = 251;
  42.         scenarioInfoCmd = 260;
  43.         importMusicCmd = 261;
  44.         lastEncounterCmd = 452;
  45.         editWallsCmd = 406;
  46.         editDoorsCmd = 407;
  47.         editObjectsCmd = 408;
  48.         editOtherCmd = 410;
  49.         editEnemiesCmd = 411;
  50.  
  51.         titleArtCmd = 270;
  52.         intermissionArtCmd = 271;
  53.         bjArtCmd = 272;
  54.         faceArt320Cmd = 273;
  55.         faceArt512Cmd = 274;
  56.         faceArt640Cmd = 275;
  57.         getPsychedArtCmd = 276;
  58.  
  59.         titleColoursCmd = 280;
  60.         gameColoursCmd = 281;
  61.         intermissionColoursCmd = 282;
  62.  
  63.         stdWallListID = 137;
  64.  
  65.         mapListBrgrID = 146;
  66.         musicListBrgrID = 147;
  67.         wallListBrgrID = 137;
  68.         firstLevelBrgrID = 200;
  69.         maxLevelBrgrID = 299;
  70.  
  71.         firstCustomArtBrgrID = $2000;
  72.  
  73.         firstImagePictID = $4000;
  74.         firstCustID = 128;
  75.  
  76.         miscBrgrNameIDBase = 1000;
  77.  
  78.         saveLevelsDlogID = 136;
  79.         wolfEditFileItem = 10;
  80.         scenarioFileItem = 11;
  81.  
  82.     type
  83.  
  84.         CustHandle = ^CustPtr;
  85.         CustPtr = ^CustRecord;
  86.         CustRecord = array[0..255] of integer;
  87.  
  88.     var
  89.  
  90.         gStdWallList: WallListHandle;
  91.  
  92.     procedure IUMapListDoc;
  93.     begin
  94.         gStdWallList := WallListHandle(GetResource('BRGR', stdWallListID));
  95.     end;
  96.  
  97.     procedure UpdateArtEditPalettes (mapList: TMapListDoc);
  98.  
  99.         procedure CheckWindow (win: TWindow);
  100.         begin
  101.             if member(win, TArtEditDialog) then
  102.                 with TArtEditDialog(win) do
  103.                     if fPalette <> nil then
  104.                         fPalette.Invalidate;
  105.         end;
  106.  
  107.     begin {UpdateArtEditPalettes}
  108.         mapList.EachWindowDo(CheckWindow);
  109.     end;
  110.  
  111.     procedure TMapListDoc.SetupMenus;
  112.         var
  113.             cmd: integer;
  114.             thisEncounterCmd: integer;
  115.             minEncounterCmd: integer;
  116.     begin
  117.         EnableCmd(scenarioInfoCmd);
  118.         EnableCmd(buildScenarioCmd);
  119.         EnableCmd(rebuildScenarioCmd);
  120.         thisEncounterCmd := firstEncounterCmd + fVersion.encounter - 1;
  121.         minEncounterCmd := firstEncounterCmd + fVersion.minEncounter - 1;
  122.         for cmd := firstEncounterCmd to lastEncounterCmd do
  123.             if cmd >= minEncounterCmd then
  124.                 EnableCmd(cmd);
  125.         CheckCmd(thisEncounterCmd, true);
  126.         EnableCmd(editWallsCmd);
  127.         EnableCmd(editDoorsCmd);
  128.         EnableCmd(editObjectsCmd);
  129.         EnableCmd(editOtherCmd);
  130.         EnableCmd(editEnemiesCmd);
  131.         EnableCmd(titleArtCmd);
  132.         EnableCmd(getPsychedArtCmd);
  133.         EnableCmd(intermissionArtCmd);
  134.         EnableCmd(bjArtCmd);
  135.         EnableCmd(faceArt320Cmd);
  136.         EnableCmd(faceArt512Cmd);
  137.         EnableCmd(faceArt640Cmd);
  138.         EnableCmd(titleColoursCmd);
  139.         EnableCmd(gameColoursCmd);
  140.         EnableCmd(intermissionColoursCmd);
  141.         EnableCmd(importMusicCmd);
  142.         inherited SetupMenus;
  143.     end;
  144.  
  145.     procedure TMapListDoc.DoMenuCommand (cmdNumber: integer);
  146.         const
  147.             secondEncounterCmd = firstEncounterCmd + 1;
  148.     begin
  149.         case cmdNumber of
  150.             scenarioInfoCmd: 
  151.                 EditScenarioInfo(self);
  152.             buildScenarioCmd: 
  153.                 DoBuildScenario;
  154.             rebuildScenarioCmd: 
  155.                 DoRebuildScenario;
  156.             editWallsCmd: 
  157.                 EditWalls(self);
  158.             firstEncounterCmd..lastEncounterCmd:  begin
  159.                     SetEncounter(cmdNumber - firstEncounterCmd + 1);
  160.         {$IFC NOT Demo}
  161.                     UpdateArtEditPalettes(self);
  162.         {$ENDC}
  163.                 end;
  164. {$IFC Demo}
  165.             editDoorsCmd, editObjectsCmd, editOtherCmd, editEnemiesCmd,{}
  166.             titleArtCmd, getPsychedArtCmd, intermissionArtCmd, bjArtCmd, {}
  167.             faceArt320Cmd, faceArt512Cmd, faceArt640Cmd, titleColoursCmd, {}
  168.             intermissionColoursCmd, gameColoursCmd, importMusicCmd: 
  169.                 OnlyInFullVersion;
  170. {$ELSEC}
  171.             editDoorsCmd: 
  172.                 EditDoors(self);
  173.             editObjectsCmd: 
  174.                 EditObjects(self);
  175.             editOtherCmd: 
  176.                 EditOther(self);
  177.             editEnemiesCmd: 
  178.                 EditEnemies(self);
  179.             titleArtCmd: 
  180.                 EditBigArt(self, titleArt);
  181.             getPsychedArtCmd: 
  182.                 EditBigArt(self, getPsychedArt);
  183.             intermissionArtCmd: 
  184.                 EditBigArt(self, intermissionArt);
  185.             bjArtCmd: 
  186.                 EditMultiArt(self, bjArt);
  187.             faceArt320Cmd: 
  188.                 EditMultiArt(self, faceArt320);
  189.             faceArt512Cmd: 
  190.                 EditMultiArt(self, faceArt512);
  191.             faceArt640Cmd: 
  192.                 EditMultiArt(self, faceArt640);
  193.             titleColoursCmd: 
  194.                 EditColours(self, titleCTabID);
  195.             intermissionColoursCmd: 
  196.                 EditColours(self, intermissionCTabID);
  197.             gameColoursCmd: 
  198.                 EditColours(self, gameCTabID);
  199.             importMusicCmd: 
  200.                 EditMusic(self);
  201. {$ENDC}
  202.             otherwise
  203.                 inherited DoMenuCommand(cmdNumber);
  204.         end;
  205.     end;
  206.  
  207.     function NewWallArtList: WallArtListHandle;
  208.     begin
  209.         NewWallArtList := WallArtListHandle(NewHandle(sizeof(WallArtList)));
  210.     end;
  211.  
  212.     procedure DisposeWallArtList (wal: WallArtListHandle);
  213.         var
  214.             i: integer;
  215.  
  216.         procedure DisposeWallArtPair (wale1, wale2: WallArtListEntry);
  217.         begin
  218.             if wale2.art <> wale1.art then
  219.                 DisposHandle(Handle(wale2.art));
  220.             DisposeHandle(Handle(wale1.art));
  221.         end;
  222.  
  223.     begin {DisposeWallArtList}
  224.         for i := 0 to 31 do
  225.             DisposeWallArtPair(wal^^[2 * i], wal^^[2 * i + 1]);
  226.         DisposHandle(Handle(wal));
  227.     end;
  228.  
  229.     procedure DisposeObjectArtList (p: TObjectArtList);
  230.         var
  231.             q: TObjectArtList;
  232.     begin
  233.         while p <> nil do begin
  234.                 q := p;
  235.                 p := p.next;
  236.                 DisposHandle(Handle(q.art));
  237.                 dispose(q);
  238.             end;
  239.     end;
  240.  
  241.     procedure RequiresVersion (name: string; v: integer);
  242.         var
  243.             d: integer;
  244.     begin
  245.         if v mod 10 = 0 then
  246.             d := 1
  247.         else
  248.             d := 2;
  249.         ParamText(name, StringOf(v / 100 : 1 : d), '', '');
  250.         DoAlert(requiresVersionAlrtID);
  251.     end;
  252.  
  253.     procedure ChangeImageMask (var mask: CustomMaskSet; code: integer; value: boolean);
  254.     begin
  255.         if value then begin
  256.                 mask := mask + [code];
  257.             end
  258.         else
  259.             mask := mask - [code];
  260.     end;
  261.  
  262.     procedure TMapListDoc.IMapListDoc;
  263.     begin
  264.         IDocument(wolfEdit2DocType);
  265.         fVersion.wolfEdit := unknownVersion;
  266.         fVersion.encounter := 1;
  267.         fVersion.minEncounter := 1;
  268.         fName := nil;
  269.         fPict := nil;
  270.         fTitleMusic := DefaultTitleMusic;
  271.         fInterMusic := DefaultBetweenLevelsMusic;
  272.         fNumLevels := 0;
  273.         fIndex := nil;
  274.         fWallArt := nil;
  275.         fObjectArt := nil;
  276.         fImageCache := gDefaultImageCache;
  277.         fOwnImageCache := false;
  278.         fImagesChanged := false;
  279.   {$IFC SaveAsScenario}
  280.         fFileCreator := gCreator;
  281.   {$ENDC}
  282.         fHasScenarioFile := false;
  283.         fScenarioVRefNum := 0;
  284.         fScenarioFileName := '';
  285.         fMusic := nil;
  286.         fMiscBrgrs := nil;
  287.         fMiscRsrcs := nil;
  288.     end;
  289.  
  290.     procedure TMapListDoc.DisposeContents;
  291.         var
  292.             i: integer;
  293.             p: LevelInfoHandle;
  294.             h: LevelHandle;
  295.             m: TMusicRsrcList;
  296.             b: TBrgrList;
  297.             r: TRsrcList;
  298.     begin
  299.         DisposHandle(Handle(fName));
  300.         DisposHandle(Handle(fPict));
  301.         for i := 1 to fNumLevels do begin
  302.                 FreeObject(fIndex^^[i].map);
  303.                 with fIndex^^[i] do begin
  304.                         p := info;
  305.                         h := resource;
  306.                     end;
  307.                 if p <> nil then
  308.                     DisposeLevelInfo(p);
  309.                 if h <> nil then
  310.                     DisposeLevel(h);
  311.             end;
  312.         DisposHandle(Handle(fIndex));
  313.         fIndex := nil;
  314.         fNumLevels := 0;
  315.         if fWallArt <> nil then begin
  316.                 DisposeWallArtList(fWallArt);
  317.                 fWallArt := nil;
  318.             end;
  319.         if fObjectArt <> nil then begin
  320.                 DisposeObjectArtList(fObjectArt);
  321.                 fObjectArt := nil;
  322.             end;
  323.         if fOwnImageCache & (fImageCache <> nil) then begin
  324.                 fImageCache.Free;
  325.                 fImageCache := nil;
  326.                 fOwnImageCache := false;
  327.             end;
  328.         while fMusic <> nil do begin
  329.                 m := fMusic;
  330.                 fMusic := fMusic.next;
  331.                 DisposHandle(m.song);
  332.                 DisposHandle(m.midi);
  333.                 dispose(m);
  334.             end;
  335.         while fMiscBrgrs <> nil do begin
  336.                 b := fMiscBrgrs;
  337.                 fMiscBrgrs := b.next;
  338.                 DisposHandle(b.brgr);
  339.                 dispose(b);
  340.             end;
  341.         while fMiscRsrcs <> nil do begin
  342.                 r := fMiscRsrcs;
  343.                 fMiscRsrcs := fMiscRsrcs.next;
  344.                 DisposHandle(r.data);
  345.                 dispose(r);
  346.             end;
  347.     end;
  348.  
  349.     procedure TMapListDoc.SetNumLevels (n: integer);
  350.     begin
  351.         if fIndex = nil then
  352.             fIndex := IndexHandle(NewHandle(0));
  353.         if fIndex <> nil then begin
  354.                 fNumLevels := n;
  355.                 SetHandleSize(Handle(fIndex), n * sizeof(IndexEntry));
  356.             end;
  357.     end;
  358.  
  359.     procedure TMapListDoc.DoNew;
  360.     begin
  361.         fVersion.wolfEdit := thisVersion;
  362.         fVersion.encounter := gEncounter;
  363.         NewLevel;
  364.     end;
  365.  
  366. {$IFC SaveAsScenario}
  367.     var
  368.         gInited: boolean;
  369.         gFileType: integer;
  370.  
  371.     function SaveAsFilter (dlog: DialogPtr; var e: EventRecord; var itemHit: integer): boolean;
  372.     begin
  373.         if not gInited then begin
  374.                 SetDlgIValue(dlog, gFileType, 1);
  375.                 gInited := true;
  376.             end;
  377.         SaveAsFilter := false;
  378.     end;
  379.  
  380.     function SaveAsHook (item: integer; dlog: DialogPtr): integer;
  381.     begin
  382.         case item of
  383.             wolfEditFileItem, scenarioFileItem: 
  384.                 if gFileType <> item then begin
  385.                         SetDlgIValue(dlog, gFileType, 0);
  386.                         gFileType := item;
  387.                         SetDlgIValue(dlog, gFileType, 1);
  388.                     end;
  389.             otherwise
  390.                 ;
  391.         end;
  392.         SaveAsHook := item;
  393.     end;
  394.  
  395.     function TMapListDoc.DoSaveAs: boolean;
  396.         var
  397.             where: Point;
  398.             reply: SFReply;
  399.             defaultName: Str255;
  400.             prompt: Str255;
  401.     begin
  402.         SetPt(where, 100, 75);
  403.         if fHasFile then
  404.             defaultName := fFileName
  405.         else
  406.             defaultName := '';
  407.         prompt := GetString(gStdIDBase + saveAsPromptStrID)^^;
  408.         ParamText(fFileName, '', '', '');
  409.         if fFileCreator = 'WOLF' then
  410.             gFileType := scenarioFileItem
  411.         else
  412.             gFileType := wolfEditFileItem;
  413.         gInited := false;
  414.         SFPPutFile(where, prompt, defaultName, @SaveAsHook, reply, saveLevelsDlogID, @SaveAsFilter);
  415.         if reply.good then begin
  416.                 HaveFile(reply.vRefNum, reply.fName);
  417.                 if gFileType = scenarioFileItem then begin
  418.                         fFileCreator := 'WOLF';
  419.                         fFileType := 'MAPS';
  420.                     end
  421.                 else begin
  422.                         fFileCreator := gCreator;
  423.                         fFileType := 'W3L2';
  424.                     end;
  425.                 DoSaveAs := Write;
  426.             end
  427.         else
  428.             DoSaveAs := false;
  429.     end;
  430.  
  431.     function TMapListDoc.Write: boolean;
  432.         var
  433.             info: FInfo;
  434.             done: boolean;
  435.             fileName: Str255;
  436.  
  437.         procedure Check (result: OSErr);
  438.         begin
  439.             if result <> noErr then begin
  440.                     ErrorAlert(couldntSetCreatorAlrtID, fFileName, result);
  441.                     Write := false;
  442.                     exit(Write);
  443.                 end;
  444.         end;
  445.  
  446.     begin {Write}
  447.         done := inherited Write;
  448.         if done then begin
  449.                 fileName := fFileName;
  450.                 Check(GetFInfo(fileName, fVRefNum, info));
  451.                 info.fdCreator := fFileCreator;
  452.                 Check(SetFInfo(fileName, fVRefNum, info));
  453.             end;
  454.         Write := done;
  455.     end;
  456. {$ENDC}
  457.  
  458.     procedure TMapListDoc.NewLevel;
  459.         var
  460.             prevInfo: LevelInfoHandle;
  461.     begin
  462.         SetNumLevels(fNumLevels + 1);
  463.         with fIndex^^[fNumLevels] do begin
  464.                 info := NewLevelInfo;
  465.                 resource := nil;
  466.                 map := nil;
  467.                 if fNumLevels > 1 then
  468.                     prevInfo := fIndex^^[fNumLevels - 1].info
  469.                 else
  470.                     prevInfo := nil;
  471.                 with info^^ do begin
  472.                         mapListEntry.nextLevel := -1;
  473.                         mapListEntry.altNextLevel := -1;
  474.                         mapListEntry.parTime := 60;
  475.                         if prevInfo <> nil then begin
  476.                                 mapListEntry.majorFloor := prevInfo^^.mapListEntry.majorFloor;
  477.                                 mapListEntry.minorFloor := prevInfo^^.mapListEntry.minorFloor + 1;
  478.                             end
  479.                         else begin
  480.                                 mapListEntry.majorFloor := 1;
  481.                                 mapListEntry.minorFloor := 1;
  482.                             end;
  483.                         music := DefaultLevelMusic;
  484.                     end;
  485.             end;
  486.     end;
  487.  
  488.     procedure TMapListDoc.OpenLevel (num: integer);
  489.         var
  490.             map: TMap;
  491.             h: LevelHandle;
  492.     begin
  493.         h := fIndex^^[num].resource;
  494.         map := fIndex^^[num].map;
  495.         if map = nil then begin
  496.                 new(map);
  497.                 map.IMap(self, num);
  498.                 fIndex^^[num].map := map;
  499.                 if h <> nil then
  500.                     map.LoadFromResource(h);
  501.                 map.MakeWindow;
  502.             end;
  503.         map.fView.fFrame.fWindow.Select;
  504.     end;
  505.  
  506.     procedure TMapListDoc.CloseLevel (num: integer);
  507.         var
  508.             map: TMap;
  509.  
  510.         procedure Check (result: OSErr);
  511.         begin
  512.             if result <> noErr then begin
  513.                     LevelError('close', num, result);
  514.                     exit(CloseLevel);
  515.                 end;
  516.         end;
  517.  
  518.     begin {CloseLevel}
  519.         map := fIndex^^[num].map;
  520.         if map <> nil then begin
  521.                 Check(UpdateResource(num));
  522.                 map.Free;
  523.             end;
  524.     end;
  525.  
  526.     procedure TMapListDoc.InsertLevel (num: integer; p: LevelInfoHandle; h: LevelHandle);
  527.         var
  528.             i: integer;
  529.     begin
  530.         SetNumLevels(fNumLevels + 1);
  531.         for i := fNumLevels downto num + 1 do
  532.             fIndex^^[i] := fIndex^^[i - 1];
  533.         with fIndex^^[num] do begin
  534.                 info := p;
  535.                 resource := h;
  536.                 map := nil;
  537.             end;
  538.         Changed;
  539.     end;
  540.  
  541.     function TMapListDoc.CutLevel (num: integer; var p: LevelInfoHandle; var h: LevelHandle): OSErr;
  542.         var
  543.             i: integer;
  544.             e: IndexEntry;
  545.  
  546.         procedure Check (result: OSErr);
  547.         begin
  548.             if result <> noErr then begin
  549.                     CutLevel := result;
  550.                     exit(CutLevel);
  551.                 end;
  552.         end;
  553.  
  554.     begin
  555.         Check(UpdateResource(num));
  556.         e := fIndex^^[num];
  557.         p := e.info;
  558.         h := e.resource;
  559.         FreeObject(e.map);
  560.         for i := num to fNumLevels - 1 do
  561.             fIndex^^[i] := fIndex^^[i + 1];
  562.         SetNumLevels(fNumLevels - 1);
  563.         Changed;
  564.         CutLevel := noErr;
  565.     end;
  566.  
  567.     function TMapListDoc.GetDiskSpaceNeeded (var dataBytes, rsrcBytes: longint): OSErr;
  568.  
  569.         const
  570.             mapListHeaderSize = 2 * sizeof(integer);
  571.             mapListEntrySize = sizeof(MapListEntry);
  572.             musicListHeaderSize = 2 * sizeof(integer);
  573.             musicListEntrySize = sizeof(integer);
  574.  
  575.         var
  576.             n: integer;
  577.             h: LevelHandle;
  578.  
  579.         procedure Check (result: OSErr);
  580.         begin
  581.             if result <> noErr then begin
  582.                     GetDiskSpaceNeeded := result;
  583.                     exit(GetDiskSpaceNeeded);
  584.                 end;
  585.         end;
  586.  
  587.     begin
  588.         dataBytes := 0;
  589.         rsrcBytes := (mapListHeaderSize + musicListHeaderSize) + (mapListEntrySize + musicListEntrySize) * fNumLevels;
  590.         for n := 1 to fNumLevels do begin
  591.                 Check(UpdateResource(n));
  592.                 h := fIndex^^[n].resource;
  593.                 if h <> nil then
  594.                     rsrcBytes := rsrcBytes + GetHandleSize(Handle(h));
  595.             end;
  596.         GetDiskSpaceNeeded := noErr;
  597.     end;
  598.  
  599.     procedure TMapListDoc.AugmentFileTypes (var numTypes: integer; var typeList: SFTypeList);
  600.     begin
  601.         numTypes := 3;
  602.         typeList[1] := 'W3dL';
  603.         typeList[2] := 'MAPS';
  604.     end;
  605.  
  606.     function TMapListDoc.ReadFromFile (refNum: integer): OSErr;
  607.         var
  608.             n, maxLevel, id: integer;
  609.             h: Handle;
  610.             mapList: MapListHandle;
  611.             musicList: MusicListHandle;
  612.             info: FInfo;
  613.             fileName: Str255;
  614.  
  615.         procedure Check (result: OSErr);
  616.         begin
  617.             if (result <> noErr) & (result <> resNotFound) then begin
  618.                     ReadFromFile := result;
  619.                     exit(ReadFromFile);
  620.                 end;
  621.         end;
  622.  
  623.         procedure InitInfo (var p: LevelInfoRecord; n: integer);
  624.         begin
  625.             if (mapList <> nil) & (n <= mapList^^.numLevels) then begin
  626.                     p.mapListEntry := mapList^^.entries[n];
  627.                     if fVersion.wolfEdit = unknownVersion then
  628.                         if n < mapList^^.numLevels then
  629.                             if p.mapListEntry.nextLevel = -1 then
  630.                                 p.mapListEntry.nextLevel := n;
  631.                 end
  632.             else
  633.                 with p.mapListEntry do begin
  634.                         nextLevel := -1;
  635.                         altNextLevel := -1;
  636.                         parTime := 60;
  637.                         majorFloor := 1;
  638.                         minorFloor := n;
  639.                     end;
  640.             if musicList <> nil then
  641.                 p.music := musicList^^.levels[n]
  642.             else
  643.                 p.music := DefaultLevelMusic;
  644.         end;
  645.  
  646.         procedure GetWallArt (wle: WallListEntry; var wale: WallArtListEntry);
  647.         begin
  648.             wale.darkFlag := wle.darkFlag;
  649.             wale.mirrorFlag := wle.mirrorFlag;
  650.             wale.art := WallArtHandle(GetResource('BRGR', wle.brgrID));
  651.         end;
  652.  
  653.         procedure ReadWallArt;
  654.             var
  655.                 wallList: WallListHandle;
  656.                 i: integer;
  657.         begin
  658.             wallList := WallListHandle(Get1Resource('BRGR', wallListBrgrID));
  659.             if wallList <> nil then begin
  660.                     fWallArt := NewWallArtList;
  661.                     HLock(Handle(fWallArt));
  662.                     for i := 0 to 63 do
  663.                         GetWallArt(wallList^^.entries[i], fWallArt^^[i]);
  664.                     for i := 0 to 63 do
  665.                         DetachResource(fWallArt^^[i].art);
  666.                     HUnlock(Handle(fWallArt));
  667.                     ReleaseResource(Handle(wallList));
  668.                 end;
  669.         end;
  670.  
  671.         procedure ReadImages;
  672.             var
  673.                 pict: PicHandle;
  674.                 cust: CustHandle;
  675.                 iType: CustomImageType;
  676.                 code: integer;
  677.                 mask: CustomMaskSet;
  678.                 h: Handle;
  679.         begin
  680.             pict := PicHandle(Get1Resource('PICT', firstImagePictID));
  681.             if pict <> nil then begin
  682.                     InstallOwnImageCache;
  683.                     fImageCache.InstallPicture(pict);
  684.                     ReleaseResource(Handle(pict));
  685.           {InstallCustomMask;}
  686.                     for iType := wallImage to objectImage do begin
  687.                             cust := CustHandle(Get1Resource('CUST', firstCustID + ord(iType)));
  688.                             if cust <> nil then begin
  689.                                     mask := [];
  690.                                     for code := 0 to 255 do
  691.                                         if cust^^[code] <> 0 then begin
  692.                                                 mask := mask + [code];
  693.                                                 fImageCache.InstallImagePict(pict, cust^^[code], GetImageNum(iType, code));
  694.                                             end;
  695.                                     HLock(Handle(fImageCache));
  696.                                     fImageCache.fCustomMask[iType] := mask;
  697.                                     HUnlock(Handle(fImageCache));
  698.                                     ReleaseResource(Handle(cust));
  699.                                 end;
  700.                         end;
  701.                     h := Get1Resource('CUST', firstCustID + 2);
  702.                     Check(ResError);
  703.                     if h <> nil then begin
  704.                             BlockMove(h^, @fImageCache.fUserMask, sizeof(fImageCache.fUserMask));
  705.                             ReleaseResource(h);
  706.                         end;
  707.                 end;
  708.         end;
  709.  
  710. {$IFC NOT Demo}
  711.         procedure ReadObjectArt;
  712.             var
  713.                 id: integer;
  714.                 p: TObjecTArtList;
  715.         begin
  716.             for id := firstSpriteBrgrID to lastSpriteBrgrID do begin
  717.                     h := Get1Resource('BRGR', id);
  718.                     Check(ResError);
  719.                     if h <> nil then begin
  720.                             DetachResource(h);
  721.                             InstallObjectArt(id, ObjectArtHandle(h));
  722.                             Check(MemError);
  723.                         end;
  724.                 end;
  725.         end;
  726.  
  727.         procedure ReadMusic;
  728.             var
  729.                 p: TMusicRsrcList;
  730.                 song, midi: Handle;
  731.                 rID: integer;
  732.                 rType: ResType;
  733.                 rName: Str255;
  734.                 i, n: integer;
  735.         begin
  736.             n := Count1Resources('Midi');
  737.             for i := 1 to n do begin
  738.                     midi := Get1IndResource('Midi', i);
  739.                     Check(ResError);
  740.                     GetResInfo(midi, rID, rType, rName);
  741.                     song := Get1Resource('SONG', rID);
  742.                     if song <> nil then begin
  743.                             new(p);
  744.                             Check(MemError);
  745.                             p.id := rID;
  746.                             p.name := rName;
  747.                             p.song := song;
  748.                             p.midi := midi;
  749.                             p.next := fMusic;
  750.                             fMusic := p;
  751.                             DetachResource(song);
  752.                             DetachResource(midi);
  753.                         end
  754.                     else
  755.                         ReleaseResource(midi);
  756.                 end;
  757.         end;
  758.  
  759.         procedure ReadMiscBrgr (id: integer);
  760.             var
  761.                 p: TBrgrList;
  762.                 rID: integer;
  763.                 rType: ResType;
  764.                 rName: Str255;
  765.         begin
  766.             h := Get1Resource('BRGR', id);
  767.             if ResError <> resNotFound then
  768.                 Check(ResError);
  769.             if h <> nil then begin
  770.                     new(p);
  771.                     Check(MemError);
  772.                     GetResInfo(h, rID, rType, rName);
  773.                     DetachResource(h);
  774.                     p.brgrID := id;
  775.                     p.name := rName;
  776.                     p.brgr := h;
  777.                     p.next := fMiscBrgrs;
  778.                     fMiscBrgrs := p;
  779.                 end;
  780.         end;
  781.  
  782.         procedure ReadMiscBrgrs;
  783.             var
  784.                 id: integer;
  785.         begin
  786.             for id := firstMiscBrgrID to lastMiscBrgrID do
  787.                 if not (id in [137, 138, 146, 147]) then
  788.                     ReadMiscBrgr(id);
  789.         end;
  790. {$ENDC}
  791.  
  792.         procedure ReadPict;
  793.         begin
  794.             fPict := PicHandle(GetResource('PICT', levelPictID));
  795.             if fPict <> nil then
  796.                 DetachResource(Handle(fPict));
  797.         end;
  798.  
  799.         procedure ReadMiscRsrcs (rType: ResType);
  800.             var
  801.                 p: TRsrcList;
  802.                 i: integer;
  803.                 h: Handle;
  804.                 rName: Str255;
  805.         begin
  806.             i := 1;
  807.             while true do begin
  808.                     h := Get1IndResource(rType, i);
  809.                     if h = nil then
  810.                         exit(ReadMiscRsrcs);
  811.                     new(p);
  812.                     Check(MemError);
  813.                     GetResInfo(h, id, rType, rName);
  814.                     p.rType := rType;
  815.                     p.id := id;
  816.                     p.name := rName;
  817.                     p.data := h;
  818.                     p.next := fMiscRsrcs;
  819.                     fMiscRsrcs := p;
  820.                     DetachResource(h);
  821.                     i := i + 1;
  822.                 end;
  823.         end;
  824.  
  825.     begin {ReadFromFile}
  826.         ChangeCursor(gWatch);
  827.   {$IFC SaveAsScenario}
  828.         fileName := fFileName;
  829.         Check(GetFInfo(fileName, fVRefNum, info));
  830.         fFileType := info.fdType;
  831.         fFileCreator := info.fdCreator;
  832.   {$ENDC}
  833.         h := Get1Resource('Vers', 128);
  834.         if h <> nil then begin
  835.                 if GetHandleSize(h) = sizeof(fVersion) then
  836.                     fVersion := VersionHandle(h)^^
  837.                 else begin
  838.                         fVersion.wolfEdit := VersionHandle(h)^^.wolfEdit;
  839.                         fVersion.encounter := VersionHandle(h)^^.encounter;
  840.                         fVersion.minEncounter := fVersion.encounter;
  841.                     end;
  842.                 ReleaseResource(h);
  843.             end
  844.         else begin
  845.                 fVersion.wolfEdit := unknownVersion;
  846.                 fVersion.encounter := 1;
  847.             end;
  848.         if not gMultiEncounter then begin
  849.                 fVersion.encounter := 3;
  850.                 fVersion.minEncounter := 3;
  851.             end;
  852.         if fVersion.wolfEdit > thisVersion then begin
  853.                 RequiresVersion(fFileName, fVersion.wolfEdit);
  854.                 Check(suppressErr);
  855.             end;
  856.         mapList := MapListHandle(Get1Resource('BRGR', mapListBrgrID));
  857.         Check(ResError);
  858.         musicList := MusicListHandle(Get1Resource('BRGR', musicListBrgrID));
  859.         Check(ResError);
  860.         fTitleMusic := musicList^^.title;
  861.         fInterMusic := musicList^^.betweenLevels;
  862.         maxLevel := mapList^^.numLevels;
  863.         SetNumLevels(maxLevel);
  864.         if MemError <> noErr then
  865.             fNumLevels := 0;
  866.         Check(MemError);
  867.         HLock(Handle(fIndex));
  868.         for n := 1 to fNumLevels do
  869.             with fIndex^^[n] do begin
  870.                     info := NewLevelInfo;
  871.                     InitInfo(info^^, n);
  872.                     resource := nil;
  873.                     map := nil;
  874.                 end;
  875.         HUnlock(Handle(fIndex));
  876.         for n := 1 to maxLevel do begin
  877.                 id := mapList^^.firstLevelID + n - 1;
  878.                 h := Get1Resource('BRGR', id);
  879.                 Check(ResError);
  880.                 if h <> nil then begin
  881.                         DetachResource(h);
  882.                         fIndex^^[n].resource := LevelHandle(h);
  883.                     end;
  884.             end;
  885.         ReadWallArt;
  886.         ReadImages;
  887. {$IFC NOT Demo}
  888.         ReadObjectArt;
  889.         ReadMusic;
  890.         ReadMiscBrgrs;
  891. {$ENDC}
  892.         ReadPict;
  893.         ReadMiscRsrcs('snd ');
  894.         ReadMiscRsrcs('csnd');
  895.         ReadMiscRsrcs('INST');
  896.         ReadFromFile := noErr;
  897.     end;
  898.  
  899.     function TMapListDoc.WriteToFile (refNum: integer): OSErr;
  900.         var
  901.             h: Handle;
  902.  
  903.         procedure Abort (result: OSErr);
  904.         begin
  905.             if h <> nil then
  906.                 DisposHandle(h);
  907.             WriteToFile := result;
  908.             exit(WriteToFile);
  909.         end;
  910.  
  911.         procedure Error (lev: integer; result: OSErr);
  912.         begin
  913.             Abort(result);
  914.         end;
  915.  
  916.         procedure Check (result: OSErr);
  917.         begin
  918.             if result <> noErr then
  919.                 Abort(result);
  920.         end;
  921.  
  922.         procedure AddAndRelease (var h: Handle; rType: ResType; rID: integer; rName: Str255);
  923.             var
  924.                 hh: Handle;
  925.         begin
  926.             hh := h;
  927.             AddResource(hh, rType, rID, rName);
  928.             if ResError = noErr then begin
  929.                     h := nil;
  930.                     WriteResource(hh);
  931.                     if ResError = noErr then
  932.                         ReleaseResource(hh);
  933.                 end;
  934.         end;
  935.  
  936.         procedure WriteImages;
  937.             var
  938.                 iType: CustomImageType;
  939.                 code: integer;
  940.                 cust: CustHandle;
  941.         begin
  942.             if fOwnImageCache then begin
  943.                     HLock(Handle(fImageCache));
  944.                     with fImageCache do begin
  945.                             h := Handle(fImageCache.ExtractPicture);
  946.                             AddAndRelease(h, 'PICT', firstImagePictID, '');
  947.                             Check(ResError);
  948.                             for iType := wallImage to objectImage do begin
  949.                                     if fImageCache.fCustomMask[iType] <> [] then begin
  950.                                             h := NewHandle(sizeof(CustRecord));
  951.                                             cust := CustHandle(h);
  952.                                             for code := 0 to 255 do
  953.                                                 if code in fImageCache.fCustomMask[iType] then
  954.                                                     cust^^[code] := GetImageNum(iType, code)
  955.                                                 else
  956.                                                     cust^^[code] := 0;
  957.                                             AddAndRelease(h, 'CUST', firstCustID + ord(iType), '');
  958.                                             Check(ResError);
  959.                                         end;
  960.                                 end;
  961.                             if fUserMask[wallImage] + fUserMask[objectImage] <> [] then begin
  962.                                     h := NewHandle(sizeof(fUserMask));
  963.                                     Check(MemError);
  964.                                     BlockMove(@fUserMask, h^, sizeof(fUserMask));
  965.                                     AddAndRelease(h, 'CUST', firstCustID + 2, '');
  966.                                 end;
  967.                         end;
  968.                     HUnlock(Handle(fImageCache));
  969.                 end;
  970.         end;
  971.  
  972.     begin {WriteToFile}
  973.         if not FlushWindows then
  974.             Check(suppressErr);
  975.         h := NewHandle(sizeof(VersionRecord));
  976.         Check(MemError);
  977.         VersionHandle(h)^^ := fVersion;
  978.         VersionHandle(h)^^.wolfEdit := thisVersion;
  979.         AddResource(h, 'Vers', 128, '');
  980.         Check(ResError);
  981.         h := nil;
  982.         WriteResources(false, Error);
  983.         WriteImages;
  984.         WriteToFile := noErr;
  985.     end;
  986.  
  987.     function TMapListDoc.UpdateResource (num: integer): OSErr;
  988.         var
  989.             h, h2: LevelHandle;
  990.             map: TMap;
  991.  
  992.         procedure Check (result: OSErr);
  993.         begin
  994.             if result <> noErr then begin
  995.                     UpdateResource := result;
  996.                     exit(UpdateResource);
  997.                 end;
  998.         end;
  999.  
  1000.     begin {UpdateResource}
  1001.         map := fIndex^^[num].map;
  1002.         h := fIndex^^[num].resource;
  1003.         if (map <> nil) & ((h = nil) | (map.fChanged)) then begin
  1004.                 gCurrentCursor := GetCursor(watchCursor);
  1005.                 SetCursor(gCurrentCursor^^);
  1006.                 Check(map.CreateResource(h2, concat(GetLevelName(num), ' of ', fFileName)));
  1007.                 if h <> nil then
  1008.                     DisposeLevel(h);
  1009.                 fIndex^^[num].resource := h2;
  1010.                 map.fChanged := false;
  1011.             end;
  1012.         UpdateResource := noErr;
  1013.     end;
  1014.  
  1015. {$IFC FALSE}
  1016.     procedure TMapListDoc.DoInstall;
  1017.         var
  1018.             reply: SFReply;
  1019.     begin
  1020.         GetInstallFile(reply);
  1021.         if reply.good then
  1022.             InstallInFile(reply);
  1023.     end;
  1024. {$ENDC}
  1025.  
  1026. {$IFC FALSE}
  1027.     procedure TMapListDoc.DoInstallIn;
  1028.         var
  1029.             reply: SFReply;
  1030.     begin
  1031.         GetNewInstallFile(reply);
  1032.         if reply.good then
  1033.             InstallInFile(reply);
  1034.     end;
  1035. {$ENDC}
  1036.  
  1037.     procedure TMapListDoc.DoRebuildScenario;
  1038.     begin
  1039.         if not fHasScenarioFile then
  1040.             DoBuildScenario
  1041.         else
  1042.             BuildScenario;
  1043.     end;
  1044.  
  1045.     procedure TMapListDoc.DoBuildScenario;
  1046.         var
  1047.             reply: SFReply;
  1048.             where: Point;
  1049.     begin
  1050.         if fScenarioFileName = '' then
  1051.             fScenarioFileName := concat(fFileName, ' Scenario');
  1052.         SetPt(where, -1, -1);
  1053.         SFPutFile(where, 'Build Scenario:', fScenarioFileName, nil, reply);
  1054.         if reply.good then begin
  1055.                 fHasScenarioFile := true;
  1056.                 fScenarioVRefNum := reply.vRefNum;
  1057.                 fScenarioFileName := reply.fName;
  1058.                 BuildScenario;
  1059.             end;
  1060.     end;
  1061.  
  1062.     procedure TMapListDoc.BuildScenario;
  1063.         var
  1064.             refNum: integer;
  1065.             fileOpen: boolean;
  1066.             result: OSErr;
  1067.  
  1068.         procedure Error (lev: integer; result: OSErr);
  1069.         begin
  1070.             if (result = opWrErr) | (result = fBsyErr) then
  1071.                 ErrorAlert(buildFileBusyAlrtID, fScenarioFileName, result)
  1072.             else
  1073.                 LevelError('install', lev, result);
  1074.             if fileOpen then
  1075.                 CloseResFile(refNum);
  1076.             exit(BuildScenario);
  1077.         end;
  1078.  
  1079.         procedure Check (result: OSErr);
  1080.         begin
  1081.             if result <> noErr then
  1082.                 Error(0, result);
  1083.         end;
  1084.  
  1085.     begin {BuildScenario}
  1086.         fileOpen := false;
  1087.         result := FSDelete(fScenarioFileName, fScenarioVRefNum);
  1088.         Check(Create(fScenarioFileName, fScenarioVRefNum, 'WOLF', 'MAPS'));
  1089.         HCreateResFile(fScenarioVRefNum, 0, fScenarioFileName);
  1090.         Check(ResError);
  1091.         refNum := HOpenResFile(fScenarioVRefNum, 0, fScenarioFileName, fsRdWrPerm);
  1092.         Check(ResError);
  1093.         fileOpen := true;
  1094.         ChangeCursor(gWatch);
  1095.         WriteResources(true, Error);
  1096.         CloseResFile(refNum);
  1097.         fileOpen := false;
  1098.         Check(ResError);
  1099.     end;
  1100.  
  1101.     function TMapListDoc.GetLevelName (levelNum: integer): Str255;
  1102.         var
  1103.             p: LevelInfoHandle;
  1104.     begin
  1105.         p := fIndex^^[levelNum].info;
  1106.         GetLevelName := StringOf('Floor ', p^^.mapListEntry.majorFloor : 1, '-', p^^.mapListEntry.minorFloor : 1);
  1107.     end;
  1108.  
  1109. {Write out those resources that go in both WolfEdit files and Scenario files.}
  1110.  
  1111.     procedure TMapListDoc.WriteResources (installing: boolean; procedure Error (lev: integer; result: OSErr));
  1112.         var
  1113.             n, id: integer;
  1114.             h, hCopy: Handle;
  1115.             mapList: MapListHandle;
  1116.             musicList: MusicListHandle;
  1117.             wallList: WallListHandle;
  1118.             name: string;
  1119.  
  1120.         procedure Check (result: OSErr);
  1121.         begin
  1122.             if result <> noErr then begin
  1123.                     if mapList <> nil then
  1124.                         DisposeMapList(mapList);
  1125.                     if musicList <> nil then
  1126.                         DisposeMusicList(musicList);
  1127.                     if hCopy <> nil then
  1128.                         DisposHandle(hCopy);
  1129.                     if wallList <> nil then
  1130.                         DisposHandle(Handle(wallList));
  1131.                     Error(n, result);
  1132.                 end;
  1133.         end;
  1134.  
  1135.         function ValidateAltNextLevels: OSErr;
  1136.             var
  1137.                 i, j: integer;
  1138.                 info: LevelInfoHandle;
  1139.         begin
  1140.             for i := 1 to fNumLevels do begin
  1141.                     info := fIndex^^[i].info;
  1142.                     j := info^^.mapListEntry.altNextLevel + 1;
  1143.                     if (j < 0) | (j > fNumLevels) then begin
  1144.                             ParamText(GetLevelName(i), '', '', '');
  1145.                             if Ask(invalidAltNextLevelAlrtID) = cancel then begin
  1146.                                     ValidateAltNextLevels := suppressErr;
  1147.                                     exit(ValidateAltNextLevels);
  1148.                                 end;
  1149.                             info^^.mapListEntry.altNextLevel := -1;
  1150.                         end;
  1151.                 end;
  1152.             ValidateAltNextLevels := noErr;
  1153.         end;
  1154.  
  1155.         procedure DeleteRsrc (typ: ResType; id: integer);
  1156.             var
  1157.                 h: Handle;
  1158.         begin
  1159.             SetResLoad(false);
  1160.             h := Get1Resource(typ, id);
  1161.             if h <> nil then begin
  1162.                     RmveResource(h);
  1163.                     DisposHandle(h);
  1164.                 end;
  1165.             SetResLoad(true);
  1166.         end;
  1167.  
  1168.         procedure DeleteBrgr (id: integer);
  1169.             var
  1170.                 h: Handle;
  1171.         begin
  1172.             DeleteRsrc('BRGR', id);
  1173.         end;
  1174.  
  1175.         procedure AddRsrc (var h: univ Handle; typ: ResType; id: integer; name: string);
  1176.         begin
  1177.             DeleteRsrc(typ, id);
  1178.             AddResource(h, typ, id, name);
  1179.             Check(ResError);
  1180.             h := nil;
  1181.         end;
  1182.  
  1183.         procedure AddBrgr (var h: univ Handle; id: integer; name: string);
  1184.         begin
  1185.             AddRsrc(h, 'BRGR', id, name);
  1186.         end;
  1187.  
  1188.         procedure AddRsrcCopy (h: univ Handle; typ: ResType; id: integer; name: string);
  1189.             var
  1190.                 result: OSErr;
  1191.         begin
  1192. {$IFC FALSE}
  1193.             Check(HandToHand(h));
  1194.             hCopy := h;
  1195.             AddRsrc(hCopy, typ, id, name);
  1196. {$ELSEC}
  1197.             DeleteRsrc(typ, id);
  1198.             AddResource(h, typ, id, name);
  1199.             WriteResource(h);
  1200.             result := ResError;
  1201.             DetachResource(h);
  1202.             Check(result);
  1203. {$ENDC}
  1204.         end;
  1205.  
  1206.         procedure AddBrgrCopy (h: univ Handle; id: integer; name: string);
  1207.         begin
  1208.             AddRsrcCopy(h, 'BRGR', id, name);
  1209.         end;
  1210.  
  1211.         procedure BackupBrgr (id: integer);
  1212.             var
  1213.                 h: Handle;
  1214.                 rID: integer;
  1215.                 rType: ResType;
  1216.                 rName: Str255;
  1217.         begin
  1218.             if installing then begin
  1219.                     SetResLoad(false);
  1220.                     h := GetResource('BRGR', -id);
  1221.                     if h = nil then begin
  1222.                             h := GetResource('BRGR', id);
  1223.                             if h <> nil then begin
  1224.                                     GetResInfo(h, rID, rType, rName);
  1225.                                     SetResInfo(h, -id, rName);
  1226.                                 end;
  1227.                         end;
  1228.                     if h <> nil then
  1229.                         ReleaseResource(h);
  1230.                     SetResLoad(true);
  1231.                 end;
  1232.         end;
  1233.  
  1234.         procedure RestoreBrgr (id: integer);
  1235.             var
  1236.                 h, bh: Handle;
  1237.                 rID: integer;
  1238.                 rType: ResType;
  1239.                 rName: Str255;
  1240.         begin
  1241.             if installing then begin
  1242.                     SetResLoad(false);
  1243.                     bh := GetResource('BRGR', -id);
  1244.                     if bh <> nil then begin
  1245.                             h := GetResource('BRGR', id);
  1246.                             if h <> nil then begin
  1247.                                     RmveResource(h);
  1248.                                     DisposHandle(h);
  1249.                                 end;
  1250.                             GetResInfo(bh, rID, rType, rName);
  1251.                             SetResInfo(bh, id, rName);
  1252.                             ReleaseResource(bh);
  1253.                         end;
  1254.                     SetResLoad(true);
  1255.                 end;
  1256.         end;
  1257.  
  1258.         procedure PutWallListEntry (wae: WallArtListEntry; brgrID: integer; var wle: WallListEntry);
  1259.         begin
  1260.             wle.darkFlag := wae.darkFlag;
  1261.             wle.mirrorFlag := wae.mirrorFlag;
  1262.             wle.brgrID := brgrID;
  1263.         end;
  1264.  
  1265.         procedure WriteWallArt;
  1266.             var
  1267.                 i, brgrID: integer;
  1268.                 art, prevArt: WallArtHandle;
  1269.         begin
  1270.             wallList := WallListHandle(NewHandle(sizeof(WallListRecord)));
  1271.             Check(MemError);
  1272.             wallList^^ := gStdWallList^^;
  1273.             if fWallArt <> nil then begin
  1274.                     wallList^^.numEntries := 64;
  1275.                     for i := 0 to 63 do begin
  1276.                             art := fWallArt^^[i].art;
  1277.                             if art = nil then
  1278.                                 brgrID := gStdWallList^^.entries[i].brgrID
  1279.                             else if not (odd(i) & (art = prevArt)) then begin
  1280.                                     brgrID := firstCustomArtBrgrID + i;
  1281.                                     AddBrgrCopy(art, brgrID, StringOf('Wall ', i : 1));
  1282.                                 end;
  1283.                             PutWallListEntry(fWallArt^^[i], brgrID, wallList^^.entries[i]);
  1284.                             prevArt := art;
  1285.                         end;
  1286.                 end;
  1287.             AddBrgr(wallList, wallListBrgrID, 'Wall List');
  1288.         end;
  1289.  
  1290. {$IFC NOT Demo}
  1291.         procedure WriteObjectArt;
  1292.             const
  1293.                 maxSprite = lastSpriteBrgrID - firstSpriteBrgrID;
  1294.             type
  1295.                 SpriteSet = set of 0..maxSprite;
  1296.             var
  1297.                 p: TObjectArtList;
  1298.                 sprites: SpriteSet;
  1299.                 i, id: integer;
  1300.         begin
  1301.             sprites := [];
  1302.             p := fObjectArt;
  1303.             while p <> nil do begin
  1304.                     id := p.brgrID;
  1305.                     i := id - firstSpriteBrgrID;
  1306.                     sprites := sprites + [i];
  1307.                     BackupBrgr(id);
  1308.                     AddBrgrCopy(p.art, id, StringOf('Sprite ', i : 1));
  1309.                     p := p.next;
  1310.                 end;
  1311.             for id := firstSpriteBrgrID to lastSpriteBrgrID do
  1312.                 if not (id - firstSpriteBrgrID in sprites) then
  1313.                     RestoreBrgr(id);
  1314.         end;
  1315.  
  1316.         procedure WriteMusic;
  1317.             type
  1318.                 WordPtr = ^integer;
  1319.             var
  1320.                 p: TMusicRsrcList;
  1321.                 i: integer;
  1322.         begin
  1323.             p := fMusic;
  1324.             while p <> nil do begin
  1325.                     WordPtr(p.song^)^ := p.id;
  1326.                     AddRsrcCopy(p.song, 'SONG', p.id, p.name);
  1327.                     AddRsrcCopy(p.midi, 'Midi', p.id, p.name);
  1328.                     id := id + 1;
  1329.                     p := p.next;
  1330.                 end;
  1331.         end;
  1332.  
  1333.         procedure WriteMiscBrgrs;
  1334.             var
  1335.                 p: TBrgrList;
  1336.         begin
  1337.             p := fMiscBrgrs;
  1338.             while p <> nil do begin
  1339.                     if p.brgr <> nil then
  1340.                         AddBrgrCopy(p.brgr, p.brgrID, p.name);
  1341.                     p := p.next;
  1342.                 end;
  1343.         end;
  1344. {$ENDC}
  1345.  
  1346.         procedure SupplyDarkTable;
  1347.             var
  1348.                 dt: Handle;
  1349.         begin
  1350.             if GetMiscBrgr(136) = nil then begin
  1351.                     dt := GetResource('BRGR', 136);
  1352.                     AddBrgrCopy(dt, 136, 'DarkTable');
  1353.                     ReleaseResource(dt);
  1354.                 end;
  1355.         end;
  1356.  
  1357.         procedure WritePict;
  1358.         begin
  1359.             if fPict <> nil then
  1360.                 AddRsrcCopy(fPict, 'PICT', levelPictID, '');
  1361.         end;
  1362.  
  1363.         procedure WriteMiscRsrcs;
  1364.             var
  1365.                 p: TRsrcList;
  1366.         begin
  1367.             p := fMiscRsrcs;
  1368.             while p <> nil do begin
  1369.                     if p.data <> nil then
  1370.                         AddRsrcCopy(p.data, p.rType, p.id, p.name);
  1371.                     p := p.next;
  1372.                 end;
  1373.         end;
  1374.  
  1375.     begin {WriteResources}
  1376.         if not FlushWindows then
  1377.             Check(suppressErr);
  1378.         mapList := nil;
  1379.         musicList := nil;
  1380.         hCopy := nil;
  1381.         wallList := nil;
  1382.         n := 0;
  1383.         ChangeCursor(gWatch);
  1384.         Check(ValidateAltNextLevels);
  1385.         DeleteBrgr(mapListBrgrID);
  1386.         DeleteBrgr(musicListBrgrID);
  1387.         mapList := CreateMapListResource(installing);
  1388.         Check(MemError);
  1389.         musicList := CreateMusicListResource;
  1390.         Check(MemError);
  1391.         AddResource(Handle(mapList), 'BRGR', mapListBrgrID, 'Map List');
  1392.         Check(ResError);
  1393.         ReleaseResource(Handle(mapList));
  1394.         mapList := nil;
  1395.         AddResource(Handle(musicList), 'BRGR', musicListBrgrID, 'Music List');
  1396.         Check(ResError);
  1397.         ReleaseResource(Handle(musicList));
  1398.         musicList := nil;
  1399.         for n := 1 to fNumLevels do begin
  1400.                 Check(UpdateResource(n));
  1401.                 h := Handle(fIndex^^[n].resource);
  1402.                 if h <> nil then begin
  1403.                         Check(HandToHand(h));
  1404.                         hCopy := h;
  1405.                         id := firstLevelBrgrID + n - 1;
  1406.                         DeleteBrgr(id);
  1407.                         name := GetLevelName(n);
  1408.                         if installing then
  1409.                             name := concat(name, ' of ', fFileName);
  1410.                         AddResource(hCopy, 'BRGR', id, name);
  1411.                         Check(ResError);
  1412.                         ReleaseResource(hCopy);
  1413.                         hCopy := nil;
  1414.                     end;
  1415.             end;
  1416.         WriteWallArt;
  1417. {$IFC NOT Demo}
  1418.         WriteObjectArt;
  1419.         WriteMusic;
  1420.         WriteMiscBrgrs;
  1421. {$ENDC}
  1422.         SupplyDarkTable;
  1423.         WritePict;
  1424.         WriteMiscRsrcs;
  1425.     end;
  1426.  
  1427.     function TMapListDoc.CreateMapListResource (installing: boolean): MapListHandle;
  1428.         var
  1429.             h: MapListHandle;
  1430.             n: integer;
  1431.     begin
  1432.         h := NewMapList(fNumLevels);
  1433.         if h <> nil then begin
  1434.                 h^^.numLevels := fNumLevels;
  1435.                 h^^.firstLevelID := firstLevelBrgrID;
  1436.                 for n := 1 to fNumLevels do begin
  1437.                         h^^.entries[n] := fIndex^^[n].info^^.mapListEntry;
  1438.                         with h^^.entries[n] do
  1439.                             if n < fNumLevels then
  1440.                                 nextLevel := n
  1441.                             else
  1442.                                 nextLevel := -1;
  1443.                     end;
  1444.             end;
  1445.         CreateMapListResource := h;
  1446.     end;
  1447.  
  1448.     function TMapListDoc.CreateMusicListResource: MusicListHandle;
  1449.         var
  1450.             h: MusicListHandle;
  1451.             i: integer;
  1452.     begin
  1453.         h := NewMusicList(fNumLevels);
  1454.         if h <> nil then begin
  1455.                 h^^.title := fTitleMusic;
  1456.                 h^^.betweenLevels := fInterMusic;
  1457.                 for i := 1 to fNumLevels do
  1458.                     h^^.levels[i] := fIndex^^[i].info^^.music;
  1459.             end;
  1460.         CreateMusicListResource := h;
  1461.     end;
  1462.  
  1463.     procedure TMapListDoc.LevelError (doing: string; lev: integer; result: OSErr);
  1464.         var
  1465.             what: string;
  1466.             alrt: integer;
  1467.     begin
  1468.         if (result <> noErr) & (result <> suppressErr) then begin
  1469.                 what := fFileName;
  1470.                 if lev > 0 then
  1471.                     what := concat(GetLevelName(lev), ' of ', what);
  1472.                 case result of
  1473.                     memFullErr: 
  1474.                         alrt := noMemForLevelAlrtID;
  1475.                     otherwise
  1476.                         alrt := couldntOperateOnLevelAlrtID;
  1477.                 end;
  1478.                 ParamText('install', what, StringOf(result : 1), '');
  1479.                 DoAlert(alrt);
  1480.             end;
  1481.     end;
  1482.  
  1483.     function TMapListDoc.GetWallArtList: WallArtListHandle;
  1484.         var
  1485.             i: integer;
  1486.  
  1487.         procedure InitEntry (j: integer; d, m: boolean);
  1488.         begin
  1489.             with fWallArt^^[j] do begin
  1490.                     art := nil;
  1491.                     darkFlag := d;
  1492.                     mirrorFlag := m;
  1493.                 end;
  1494.         end;
  1495.  
  1496.     begin {TMapListDoc.GetWallArtList}
  1497.         if fWallArt = nil then begin
  1498.                 fWallArt := NewWallArtList;
  1499.                 for i := 0 to 28 do begin
  1500.                         InitEntry(2 * i, false, false);
  1501.                         InitEntry(2 * i + 1, true, false);
  1502.                     end;
  1503.                 InitEntry(58, false, false);
  1504.                 for i := 59 to 62 do
  1505.                     InitEntry(i, false, true);
  1506.                 InitEntry(63, false, false);
  1507.             end;
  1508.         GetWallArtList := fWallArt;
  1509.     end;
  1510.  
  1511. {$IFC FALSE}
  1512.     function TMapListDoc.GetObjectArtList: ObjectArtListHandle;
  1513.     begin
  1514.         if fObjectArt = nil then
  1515.             fObjectArt := NewObjectArtList;
  1516.         GetObjectArtList := fObjectArt;
  1517.     end;
  1518. {$ENDC}
  1519.  
  1520.     function TMapListDoc.GetObjectArt (brgrID: integer): ObjectArtHandle;
  1521.         var
  1522.             p: TObjectArtList;
  1523.     begin
  1524.         p := fObjectArt;
  1525.         while p <> nil do begin
  1526.                 if p.brgrID = brgrID then begin
  1527.                         GetObjectArt := p.art;
  1528.                         exit(GetObjectArt);
  1529.                     end;
  1530.                 p := p.next;
  1531.             end;
  1532.         GetObjectArt := nil;
  1533.     end;
  1534.  
  1535.     procedure TMapListDoc.InstallObjectArt (brgrID: integer; art: ObjectArtHandle);
  1536.         var
  1537.             p: TObjectArtList;
  1538.  
  1539.         procedure AddNode;
  1540.             var
  1541.                 p: TObjectArtList;
  1542.         begin
  1543.             if art <> nil then begin
  1544.                     new(p);
  1545.                     if MemError <> noErr then
  1546.                         exit(InstallObjectArt);
  1547.                     p.brgrID := brgrID;
  1548.                     p.art := art;
  1549.                     p.next := fObjectArt;
  1550.                     fObjectArt := p;
  1551.                 end;
  1552.         end;
  1553.  
  1554.         procedure DeleteNode (p: TObjectArtList);
  1555.             var
  1556.                 q: TObjectArtList;
  1557.         begin
  1558.             if p = fObjectArt then
  1559.                 fObjectArt := p.next
  1560.             else begin
  1561.                     q := fObjectArt;
  1562.                     while q.next <> p do
  1563.                         q := q.next;
  1564.                     q.next := p.next;
  1565.                 end;
  1566.             dispose(p);
  1567.         end;
  1568.  
  1569.     begin {TMapListDoc.InstallObjectArt }
  1570.         p := fObjectArt;
  1571.         while (p <> nil) & (p.brgrID <> brgrID) do
  1572.             p := p.next;
  1573.         if p = nil then
  1574.             AddNode
  1575.         else begin
  1576.                 DisposHandle(Handle(p.art));
  1577.                 if art <> nil then
  1578.                     p.art := art
  1579.                 else
  1580.                     DeleteNode(p);
  1581.             end;
  1582.         fChanged := true;
  1583.     end;
  1584.  
  1585.     function TMapListDoc.GetMiscBrgr (id: integer): Handle;
  1586.         var
  1587.             p: TBrgrList;
  1588.     begin
  1589.         p := fMiscBrgrs;
  1590.         while (p <> nil) & (p.brgrID <> id) do
  1591.             p := p.next;
  1592.         if p <> nil then
  1593.             GetMiscBrgr := p.brgr
  1594.         else
  1595.             GetMiscBrgr := nil;
  1596.     end;
  1597.  
  1598.     procedure TMapListDoc.InstallMiscBrgr (h: Handle; id: integer);
  1599.         var
  1600.             p: TBrgrList;
  1601.             nameH: StringHandle;
  1602.     begin
  1603.         p := fMiscBrgrs;
  1604.         while (p <> nil) & (p.brgrID <> id) do
  1605.             p := p.next;
  1606.         if p = nil then begin
  1607.                 new(p);
  1608.                 p.brgrID := id;
  1609.                 p.brgr := nil;
  1610.                 p.next := fMiscBrgrs;
  1611.                 fMiscBrgrs := p;
  1612.             end;
  1613.         DisposHandle(p.brgr);
  1614.         nameH := GetString(miscBrgrNameIDBase + id);
  1615.         if nameH <> nil then
  1616.             p.name := nameH^^
  1617.         else
  1618.             p.name := '';
  1619.         p.brgr := h;
  1620.     end;
  1621.  
  1622.     function TMapListDoc.GetMiscRsrc (rType: ResType; id: integer): Handle;
  1623.         var
  1624.             p: TRsrcList;
  1625.     begin
  1626.         p := fMiscRsrcs;
  1627.         while (p <> nil) & ((p.rType <> rType) or (p.id <> id)) do
  1628.             p := p.next;
  1629.         if p <> nil then
  1630.             GetMiscRsrc := p.data
  1631.         else
  1632.             GetMiscRsrc := nil;
  1633.     end;
  1634.  
  1635.     procedure TMapListDoc.InstallMiscRsrc (h: Handle; rType: ResType; id: integer; name: string);
  1636.         var
  1637.             p: TRsrcList;
  1638.     begin
  1639.         p := fMiscRsrcs;
  1640.         while (p <> nil) & ((p.rType <> rType) or (p.id <> id)) do
  1641.             p := p.next;
  1642.         if p = nil then begin
  1643.                 new(p);
  1644.                 p.rType := rType;
  1645.                 p.id := id;
  1646.                 p.data := nil;
  1647.                 p.next := fMiscRsrcs;
  1648.                 fMiscRsrcs := p;
  1649.             end;
  1650.         DisposHandle(p.data);
  1651.         p.name := name;
  1652.         p.data := h;
  1653.     end;
  1654.  
  1655.     procedure TMapListDoc.PlotWall (code: integer; r: Rect);
  1656.     begin
  1657.         if WallAvailable(code) then begin
  1658.                 HLock(Handle(fImageCache));        {Set membership testing can MOVE MEMORY!!!}
  1659.                 if code in fImageCache.fCustomMask[wallImage] then
  1660.                     fImageCache.PlotWall(code, r)
  1661.                 else
  1662.                     gDefaultImageCache.PlotWall(code, r);
  1663.                 HUnlock(Handle(fImageCache));
  1664.             end
  1665.         else
  1666.             gDefaultImageCache.PlotUnknown(r);
  1667.     end;
  1668.  
  1669.     procedure TMapListDoc.PlotObject (code, dir: integer; r: Rect);
  1670.     begin
  1671.         with gVariantObjectTable[code] do
  1672.             if baseObject >= 0 then begin
  1673.                     PlotObject(baseObject, dir, r);
  1674.                     gDefaultImageCache.PlotImage(extraImage, r);
  1675.                 end
  1676.             else if ObjectAvailable(code) then begin
  1677.                     HLock(Handle(fImageCache));
  1678.                     if code in fImageCache.fCustomMask[objectImage] then
  1679.                         fImageCache.PlotObject(code, dir, r)
  1680.                     else
  1681.                         gDefaultImageCache.PlotObject(code, dir, r);
  1682.                     HUnlock(Handle(fImageCache));
  1683.                 end
  1684.             else
  1685.                 gDefaultImageCache.PlotUnknown(r);
  1686.     end;
  1687.  
  1688.     procedure TMapListDoc.PlotSound (r: Rect);
  1689.     begin
  1690.         gDefaultImageCache.PlotSound(r);
  1691.     end;
  1692.  
  1693.     function TMapListDoc.WallAvailable (code: integer): boolean;
  1694.     begin
  1695.         HLock(Handle(fImageCache));
  1696.         if code in fImageCache.fCustomMask[wallImage] then
  1697.             WallAvailable := true
  1698.         else
  1699.             WallAvailable := WallAvailableIn(code, fVersion.Encounter);
  1700.         HUnlock(Handle(fImageCache));
  1701.     end;
  1702.  
  1703.     function TMapListDoc.ObjectAvailable (code: integer): boolean;
  1704.     begin
  1705.         HLock(Handle(fImageCache));
  1706.         if code in fImageCache.fCustomMask[objectImage] then
  1707.             ObjectAvailable := true
  1708.         else
  1709.             ObjectAvailable := ObjectAvailableIn(code, fVersion.Encounter);
  1710.         HUnlock(Handle(fImageCache));
  1711.     end;
  1712.  
  1713.     function TMapListDoc.ItemAvailable (item: MapCell): boolean;
  1714.     begin
  1715.         ItemAvailable := WallAvailable(item.wall) & ObjectAvailable(item.obj);
  1716.     end;
  1717.  
  1718.     procedure TMapListDoc.InstallWallImage (code, view: integer; gWorld: GWorldPtr);
  1719.     begin
  1720.         InstallOwnImageCache;
  1721.         fImageCache.InstallWallImage(code, view, gWorld);
  1722.         HLock(Handle(fImageCache));
  1723.         ChangeImageMask(fImageCache.fCustomMask[wallImage], code, gWorld <> nil);
  1724.         HUnlock(Handle(fImageCache));
  1725.         fImagesChanged := true;
  1726.         Changed;
  1727.         UpdateImageViews;
  1728.     end;
  1729.  
  1730.     procedure TMapListDoc.InstallDoorImage (code: integer; gWorld: GWorldPtr);
  1731.     begin
  1732.         InstallOwnImageCache;
  1733.         fImageCache.InstallDoorImage(code, gWorld);
  1734.         HLock(Handle(fImageCache));
  1735.         ChangeImageMask(fImageCache.fCustomMask[objectImage], BAND(code, $FE), gWorld <> nil);
  1736.         ChangeImageMask(fImageCache.fCustomMask[objectImage], BOR(code, $01), gWorld <> nil);
  1737.         HUnlock(Handle(fImageCache));
  1738.         fImagesChanged := true;
  1739.         Changed;
  1740.         UpdateImageViews;
  1741.     end;
  1742.  
  1743.     procedure TMapListDoc.InstallObjectImage (code: integer; gWorld: GWorldPtr);
  1744.     begin
  1745.         InstallOwnImageCache;
  1746.         fImageCache.InstallObjectImage(code, gWorld);
  1747.         HLock(Handle(fImageCache));
  1748.         ChangeImageMask(fImageCache.fCustomMask[objectImage], code, gWorld <> nil);
  1749.         HUnlock(Handle(fImageCache));
  1750.         fImagesChanged := true;
  1751.         Changed;
  1752.         UpdateImageViews;
  1753.     end;
  1754.  
  1755.     procedure TMapListDoc.InstallOwnImageCache;
  1756.         var
  1757.             imageCache: TImageCache;
  1758.     begin
  1759.         if not fOwnImageCache then begin
  1760.                 new(imageCache);
  1761.                 imageCache.IImageCache;
  1762.                 fImageCache := imageCache;
  1763.                 fOwnImageCache := true;
  1764.             end;
  1765.     end;
  1766.  
  1767.     procedure TMapListDoc.Changed;
  1768.     begin
  1769.         fVersion.minEncounter := fVersion.encounter;
  1770.         inherited Changed;
  1771.     end;
  1772.  
  1773.     function TMapListDoc.FlushWindows: boolean;
  1774.  
  1775.         procedure FlushWindow (win: TWindow);
  1776.         begin
  1777.             if member(win, TXWindow) then
  1778.                 if not TXWindow(win).Flush then begin
  1779.                         FlushWindows := false;
  1780.                         exit(FlushWindows);
  1781.                     end;
  1782.         end;
  1783.  
  1784.     begin {TMapListDoc.FlushWindows}
  1785.         FlushWindows := true;
  1786.         EachWindowDo(FlushWindow);
  1787.     end;
  1788.  
  1789. end.